QtGUI模块功能详细说明,图像处理(三)
目录
一. 窗口和屏幕管理
二. 绘图和渲染
三. 图像处理
1、基础图像类与区别
1.1、Qt 图像处理概述
1.2、QImage 与 QPixmap 的核心区别
1.3、QBitmap:单色位图
1.4、QImage与QPixmap转换
1.5、QBitmap 与 QImage、QPixmap 的对比说明
2、QImage 详解:像素操作与处理
2.1、QImage 的创建与基本属性
2.2、像素的访问与修改
2.3、图像格式转换convertToFormat()
2.4、QImage 的变换
2.5、QImage 作为绘图设备
2.6、简单的 QImage 像素级处理
3、QPixmap 详解:显示优化
3.1、QPixmap 的创建
3.2、QPixmap 用于绘制
3.3、QPixmap 的显示与优化
3.4、QPixmap 在 UI 中的应用
4、图像文件处理与高级特性
4.1、QImageReader:读取图像文件
4.2、QImageWriter:写入图像文件
4.3、QMovie:动态图像播放
4.4、QImageIOHandler 与 QImageIOPlugin:自定义图像格式
5、QPicture:记录和重放绘图指令
5.1、QPicture 的概念与用途
5.2、记录和重放绘图
5.3、QPicture 的存储与加载
5.4、QPicture 与 QImage/QPixmap 的转换
5.5、示例代码
6、示例代码
6.1、使用 QLabel 显示静态图像和动画
6.2、在 Graphics View Framework 中处理和显示图像
6.3、自定义 Widget 中的图像绘制
6.4、从文件加载图像,显示,进行像素操作,保存到新文件
6.5、在后台线程中进行耗时图像处理,然后更新 UI
四. 字体和文本
五. 事件和输入处理
六. OpenGL 和硬件加速
七. 颜色和外观
八. 图标和光标
九. 平台和渲染后端
十. 国际化(GUI 相关)
一. 窗口和屏幕管理
提供跨平台窗口创建、管理以及屏幕信息访问功能。
请跳转章节,此处不再重复:QtGUI模块功能详细说明,窗口和屏幕管理(一)
二. 绘图和渲染
提供 2D 绘图功能,包括线条、形状、文本和变换。
请跳转章节,此处不再重复:QtGUI模块功能详细说明,图形绘制与渲染(二)
三. 图像处理
1、基础图像类与区别
1.1、Qt 图像处理概述
图像处理是指对数字图像进行操作以提取信息、增强效果或优化显示的过程,包括调整颜色、裁剪、缩放、滤镜应用等。
1.1.1、图像处理模块的功能
Qt 的图像处理功能主要位于 QtGui 模块中,核心类包括 QImage、QPixmap、QBitmap 和 QPainter。这些类支持:
-
图像加载与保存:支持多种格式(PNG、JPEG、BMP 等)。
-
像素级操作:直接访问和修改像素数据。
-
绘制与渲染:在屏幕或离屏表面上绘制图像。
-
硬件加速:利用 GPU 优化显示性能。
-
格式转换:在不同图像类之间转换以适应特定需求。
1.1.2、主要的图像类
-
QImage:用于像素级操作,设备无关,适合图像处理和文件 I/O。
-
QPixmap:优化用于屏幕显示,设备相关,可能利用硬件加速。
-
QBitmap:单色位图(1 位深度),常用于蒙版或简单二值图像。
1.2、QImage 与 QPixmap 的核心区别
1.2.1、QImage:像素级操作与设备无关
-
定义与特点:
-
QImage 是一个设备无关的图像类,存储在内存中,表示为像素数组。
-
提供对像素数据的直接访问,支持颜色深度(1、8、32 位等)和格式(如 RGB、ARGB)。
-
适合图像处理任务,如调整亮度、应用滤镜、颜色转换等。
-
-
主要用途:
-
图像处理:如缩放、旋转、裁剪、像素级修改。
-
文件 I/O:加载和保存图像文件(支持多种格式)。
-
跨平台操作:不受显示设备限制,适合后台处理。
-
-
优缺点
-
优点:灵活,适合复杂的图像处理任务。
-
缺点:内存占用较高,显示性能不如 QPixmap。
-
-
示例:内存中的像素数据访问:修改像素值以实现灰度转换
QImage image("example.png"); for (int y = 0; y < image.height(); ++y) {for (int x = 0; x < image.width(); ++x) {QRgb pixel = image.pixel(x, y);int gray = qGray(pixel);image.setPixel(x, y, qRgb(gray, gray, gray));} }
1.2.2、QPixmap:优化用于屏幕显示
-
定义与特点:
-
QPixmap 是一个设备相关的图像类,针对特定显示设备(如屏幕)优化。
-
内部可能使用本地图形系统资源(如 X11、DirectX 或 OpenGL),支持硬件加速。
-
不直接提供像素级访问,适合快速绘制到窗口或控件。
-
-
主要用途:
-
UI 显示:在 QWidget、QGraphicsView 或 QLabel 中显示图像。
-
快速渲染:如图标、背景图或动画帧。
-
离屏绘制:用作 QPainter 的绘制目标。
-
-
优缺点
-
优点:显示效率高,适合 GUI 应用。
-
缺点:不适合像素级操作,设备相关(跨平台需注意)。
-
-
示例:在窗口中显示图像
QPixmap pixmap("example.png"); QLabel label; label.setPixmap(pixmap); label.show();
1.3、QBitmap:单色位图
-
定义与特点:
-
QBitmap 是 QPixmap 的子类,专用于 1 位深度(单色)图像。
-
每个像素只有两种状态(通常为黑白,0 或 1)。
-
设备相关,与 QPixmap 类似,针对特定显示设备优化。
-
-
主要用途:
-
创建蒙版:用于图像透明效果或裁剪形状
-
简单二值图像:如黑白图标或文字轮廓。
-
-
示例:设置窗口蒙版实现不规则窗口
QBitmap bitmap("mask.png"); QWidget window; window.setMask(bitmap);
1.4、QImage与QPixmap转换
QImage image("example.png");
QPixmap pixmap = QPixmap::fromImage(image); // QImage -> QPixmap
QImage image2 = pixmap.toImage(); // QPixmap -> QImage
1.5、QBitmap 与 QImage、QPixmap 的对比说明
特性 | QBitmap | QImage | QPixmap |
---|---|---|---|
定义 | 单色位图(1 位深度),QPixmap 的子类,设备相关。 | 设备无关的图像类,存储像素数据,支持多种颜色深度。 | 设备相关的图像类,优化用于屏幕显示,支持多颜色深度。 |
颜色深度 | 固定 1 位(黑白,0 或 1)。 | 支持多种深度(1、8、32 位等),如 Mono、RGB、ARGB。 | 通常为显示设备支持的深度(如 32 位 ARGB),取决于平台。 |
设备相关性 | 设备相关,针对特定显示设备优化。 | 设备无关,适合跨平台操作和后台处理。 | 设备相关,依赖显示设备,可能利用硬件加速。 |
主要特点 | - 仅存储黑白像素。 - 轻量,适合蒙版。 - 继承QPixmap的渲染能力。 | - 提供像素级访问和修改。 - 灵活,支持复杂图像处理。 - 内存占用较高。 | - 高效屏幕渲染。 - 不支持像素级操作。 - 可能利用 GPU 加速。 |
主要用途 | - 创建蒙版(如窗口遮罩、透明效果)。 - 黑白图标或二值图像。 | - 图像处理(滤镜、缩放、颜色调整)。 - 文件 I/O(加载/保存)。 - 后台操作。 | - GUI 显示(如图标、背景)。 - 高效渲染到控件或场景。 - 离屏绘制。 |
像素访问 | 不直接支持,需转换为QImage访问。 | 直接支持,通过 bits()、scanLine() 或pixel()访问像素数据。 | 不支持直接像素访问,需转换为 QImage。 |
性能 | - 渲染效率高(单色,数据量小)。 - 转换到其他类型可能有开销。 | - 图像处理灵活但显示较慢(需转换到QPixmap)。 - 内存占用高。 | - 屏幕显示效率高,硬件加速支持。 - 创建和转换可能有开销。 |
2、QImage 详解:像素操作与处理
2.1、QImage 的创建与基本属性
2.1.1、QImage构造函数
用于创建空白图像或加载已有图像:
-
指定尺寸和格式:
QImage image(640, 480, QImage::Format_RGB32); // 创建 640x480 的 RGB32 图像
-
从文件加载:
QImage image("example.png"); // 加载 PNG 文件
-
从像素数据创建:
uchar data[640 * 480 * 4]; // 假设为 RGBA 数据 QImage image(data, 640, 480, QImage::Format_ARGB32);
2.1.2、图像格式 (Format) 详解
QImage::Format 枚举定义了图像的像素存储方式,常见格式包括:
-
Format_RGB32:32 位,RGB 颜色(8 位 R、G、B,8 位填充),无透明通道。
-
Format_ARGB32:32 位,RGBA 颜色(8 位 R、G、B、A),支持透明。
-
Format_Grayscale8:8 位灰度,每个像素表示灰度值(0-255)。
-
Format_Indexed8:8 位,使用颜色表(color table)映射像素值到颜色。
-
Format_Mono:1 位,单色(黑白),用于二值图像。
-
选择建议:
-
RGB32/ARGB32 适合大多数现代应用,易于处理。
-
Grayscale8 适合灰度图像,节省内存。
-
Indexed8 适合有限颜色(如 GIF)。
-
Mono 适合蒙版或二值图像。
-
2.1.3、图像属性
-
尺寸:通过 width() 和 height() 获取。
-
深度:每像素的位数,depth() 返回(如 32 表示 ARGB32)。
-
颜色空间:通过 colorSpace() 获取(通常为 sRGB)。
-
字节数:byteCount() 返回总字节数,bytesPerLine() 返回每行字节数(可能包含填充)。
2.2、像素的访问与修改
2.2.1、pixel() / setPixel(): 访问单个像素颜色
-
获取像素:pixel(x, y) 返回 QRgb(32 位颜色值,格式为 0xAARRGGBB)。
QRgb color = image.pixel(10, 10); // 获取 (10,10) 像素颜色 int red = qRed(color); // 提取红色分量
-
设置像素:setPixel(x, y, QRgb) 或 setPixelColor(x, y, QColor)。
image.setPixel(10, 10, qRgb(255, 0, 0)); // 设置为红色
2.2.2、bits() / scanLine(): 直接访问原始像素数据
-
bits():返回指向整个图像数据的 uchar* 指针。
uchar* data = image.bits(); // 访问所有像素数据
-
scanLine():返回指定行的 uchar* 指针,效率更高。
uchar* row = image.scanLine(y); // 访问第 y 行的像素数据
-
高效操作:直接操作原始数据,避免 pixel() 的开销。
for (int y = 0; y < image.height(); ++y) {QRgb* row = reinterpret_cast<QRgb*>(image.scanLine(y));for (int x = 0; x < image.width(); ++x) {row[x] = qRgb(255, 0, 0); // 设置整行为红色} }
2.3、图像格式转换 convertToFormat()
-
将图像转换为指定格式,保留或重新映射颜色。
QImage rgbImage = image.convertToFormat(QImage::Format_RGB32); QImage grayImage = image.convertToFormat(QImage::Format_Grayscale8);
-
Format_Indexed8 使用颜色表(QVector<QRgb>)映射像素值到颜色。
-
设置颜色表:
QImage indexedImage(100, 100, QImage::Format_Indexed8); QVector<QRgb> colorTable(256); for (int i = 0; i < 256; ++i) {colorTable[i] = qRgb(i, i, i); // 灰度颜色表 } indexedImage.setColorTable(colorTable);
2.4、QImage 的变换
2.4.1、QImage缩放图像到指定尺寸
-
Qt::AspectRatioMode:控制纵横比
-
IgnoreAspectRatio 忽略
-
KeepAspectRatio 保持
-
-
Qt::TransformationMode:插值算法
-
FastTransformation 快但质量低
-
SmoothTransformation 慢但平滑
-
-
QImage scaledImage = image.scaled(320, 240, Qt::KeepAspectRatio, Qt::SmoothTransformation);
2.4.2、QImage镜像水平翻转
mirrored(horizontally = false, bool vertically)
-
horizontally 水平镜像
-
vertically 垂直镜像
2.4.3、transformed()应用矩阵变换
-
旋转 rotate(angle,axis=Qt::ZAxis)
-
angle
: 旋转的角度,单位是度。 -
axis
: 旋转轴。默认情况下,Qt::ZAxis
用于 2D 变换。
-
-
镜像 (Rotation)通过旋转实现
-
transform.scale(-1, 1) 沿 Y 轴镜像(水平翻转)
-
transform.scale(1, -1) 沿 X 轴镜像(垂直翻转)
-
-
剪切 shear(qreal sh, qreal sv)
-
sh
: 水平剪切因子。 -
sv
: 垂直剪切因子。
-
-
QTransform transform; transform.rotate(45); // 旋转 45 度 QImage rotatedImage = image.transformed(transform, Qt::SmoothTransformation);
2.5、QImage 作为绘图设备
2.5.1、使用 QPainter 绘制
-
QImage 可作为 QPainter 的绘制目标,支持绘制形状、文本和图像。
2.5.2、动态生成或修改图像
-
动态生成(如验证码)
-
修改现有图像:加载图像后用 QPainter 添加水印或标注。
-
QImage image("sample.png"); QPainter painter(&image); painter.setFont(QFont("Arial", 20)); painter.drawText(10, 30, "1234"); // 绘制验证码
2.6、简单的 QImage 像素级处理
2.6.1、灰度化
将图像转换为灰度(加权平均法:Y = 0.299R + 0.587G + 0.114B)。
QImage grayscale(const QImage& input) {QImage output(input.size(), QImage::Format_Grayscale8);for (int y = 0; y < input.height(); ++y) {const QRgb* inRow = reinterpret_cast<const QRgb*>(input.scanLine(y));uchar* outRow = output.scanLine(y);for (int x = 0; x < input.width(); ++x) {QRgb pixel = inRow[x];int gray = 0.299 * qRed(pixel) + 0.587 * qGreen(pixel) + 0.114 * qBlue(pixel);outRow[x] = gray;}}return output;
}
2.6.2、调整亮度/对比度
-
亮度:每个像素值加/减偏移(需限制在 0-255)。
-
对比度:缩放像素值(公式:new = (old - 128) * contrast + 128)。
QImage adjustBrightnessContrast(const QImage& input, int brightness, float contrast) {QImage output = input.convertToFormat(QImage::Format_RGB32);for (int y = 0; y < output.height(); ++y) {QRgb* row = reinterpret_cast<QRgb*>(output.scanLine(y));for (int x = 0; x < output.width(); ++x) {QRgb pixel = row[x];int r = qBound(0, (int)((qRed(pixel) - 128) * contrast + 128 + brightness), 255);int g = qBound(0, (int)((qGreen(pixel) - 128) * contrast + 128 + brightness), 255);int b = qBound(0, (int)((qBlue(pixel) - 128) * contrast + 128 + brightness), 255);row[x] = qRgb(r, g, b);}}return output;
}
2.6.3、基本滤镜(模糊)
模糊滤镜通常使用卷积核(如均值滤波)。以下为简化的 3x3 均值模糊
QImage simpleBlur(const QImage& input) {QImage output = input.convertToFormat(QImage::Format_RGB32);for (int y = 1; y < input.height() - 1; ++y) {QRgb* outRow = reinterpret_cast<QRgb*>(output.scanLine(y));for (int x = 1; x < input.width() - 1; ++x) {int r = 0, g = 0, b = 0;// 3x3 均值滤波for (int dy = -1; dy <= 1; ++dy) {const QRgb* inRow = reinterpret_cast<const QRgb*>(input.scanLine(y + dy));for (int dx = -1; dx <= 1; ++dx) {QRgb pixel = inRow[x + dx];r += qRed(pixel);g += qGreen(pixel);b += qBlue(pixel);}}outRow[x] = qRgb(r / 9, g / 9, b / 9);}}return output;
}
3、QPixmap 详解:显示优化
3.1、QPixmap 的创建
3.1.1、从文件加载
可以通过本地文件路径或 Qt 资源文件加载图像到 QPixmap。
-
支持常见格式(如 PNG、JPEG、BMP 等)。
-
如果文件路径无效或格式不支持,pixmap.isNull() 将返回 true。
// 从本地文件加载 QPixmap pixmap("path/to/image.png"); // 或从资源文件加载 QPixmap pixmap(":/images/icon.png");
3.1.2、从 QImage 转换
QImage 是像素级图像处理类,适合像素操作。QPixmap 可通过 QImage 构造或转换。
QImage image("path/to/image.png");
QPixmap pixmap = QPixmap::fromImage(image);
3.1.3、从内存数据
通过 QByteArray 加载图像数据,可不指定格式"PNG",会自动识别。
QByteArray imageData; // 假设包含图像数据
QPixmap pixmap;
pixmap.loadFromData(imageData, "PNG");
3.2、QPixmap 用于绘制
QPixmap 作为绘图设备,适合创建复杂图像(如合成图层、动态图标)。
QPixmap pixmap(200, 200);
QPainter painter(&pixmap);
painter.fillRect(pixmap.rect(), Qt::white); // 填充背景
painter.setPen(Qt::blue);
painter.drawRect(50, 50, 100, 100); // 绘制矩形
painter.end(); // 结束绘制
3.3、QPixmap 的显示与优化
3.3.1、在 QWidget 或其他绘图设备上绘制 QPixmap
在 QWidget 的 paintEvent 中使用 QPainter 绘制 QPixma
-
避免在 paintEvent 中频繁加载 QPixmap(影响性能),应缓存到成员变量。
-
使用 painter.drawPixmap(targetRect, pixmap, sourceRect) 可绘制部分区域。
class MyWidget : public QWidget { protected:void paintEvent(QPaintEvent *) override {QPainter painter(this);QPixmap pixmap(":/images/image.png");painter.drawPixmap(0, 0, pixmap); // 在 (0,0) 绘制} };
3.3.2、缩放 QPixmap 以适应显示区域
QPixmap 支持缩放以适配目标区域,常见方法包括:
-
直接缩放:
QPixmap scaledPixmap = pixmap.scaled(100, 100, Qt::KeepAspectRatio, Qt::SmoothTransformation);
-
Qt::KeepAspectRatio:保持宽高比。
-
Qt::SmoothTransformation:平滑缩放(适合高质量显示)。
-
-
在绘制时缩放:
QPainter painter(this); painter.drawPixmap(QRect(0, 0, 100, 100), pixmap, pixmap.rect());
3.4、QPixmap 在 UI 中的应用
3.4.1、在 QLabel 中显示图片
QLabel 是显示 QPixmap 的最简单方式,适合静态图像或简单动态图像。
-
QLabel 默认不处理透明度,需设置 setAttribute(Qt::WA_TranslucentBackground)。
-
大图像可能导致性能问题,建议预缩放。
QLabel *label = new QLabel;
QPixmap pixmap(":/images/photo.jpg");
label->setPixmap(pixmap.scaled(label->size(), Qt::KeepAspectRatio));
3.4.2、在 QGraphicsPixmapItem 中显示图片
QGraphicsPixmapItem 用于 QGraphicsView 框架,适合复杂场景(如游戏、图形编辑器)。
QGraphicsScene *scene = new QGraphicsScene;
QGraphicsPixmapItem *item = new QGraphicsPixmapItem(QPixmap(":/images/sprite.png"));
scene->addItem(item);
QGraphicsView *view = new QGraphicsView(scene);
3.4.3、作为图标、鼠标光标
图标和光标通常需要小尺寸图像(16x16 或 32x32),确保图像透明区域正确处理(如 PNG 的 alpha 通道)。
-
图标:
QIcon icon(QPixmap(":/images/icon.png")); QPushButton *button = new QPushButton; button->setIcon(icon);
-
鼠标光标:
QPixmap cursorPixmap(":/images/cursor.png"); QCursor cursor(cursorPixmap, 0, 0); // 设置热点 QApplication::setOverrideCursor(cursor);
4、图像文件处理与高级特性
4.1、QImageReader:读取图像文件
QImageReader 是 Qt 提供的用于读取图像文件的类,支持多种图像格式,适合从文件或设备中加载图像,并提供灵活的读取控制。
4.1.1、支持的图像格式
-
获取支持的格式:通过静态方法 QImageReader::supportedImageFormats() 获取当前 Qt 编译时支持的图像格式列表(如 PNG、JPEG、GIF、BMP 等)。
QList<QByteArray> formats = QImageReader::supportedImageFormats(); for (const QByteArray &format : formats) {qDebug() << "Supported format:" << format; }
-
格式支持依赖于 Qt 的编译配置和安装的插件。例如,某些格式(如 WebP)可能需要额外的插件支持。
-
使用 QImageReader::supportedMimeTypes() 获取支持的 MIME 类型。
4.1.2、从文件或设备读取图像
-
从文件读取:
QImageReader reader("image.png"); QImage image; if (reader.read(&image)) {// 图像读取成功 } else {qDebug() << "Error:" << reader.errorString(); }
-
从设备读取(如 QFile、QBuffer 等):
QFile file("image.jpg"); if (file.open(QIODevice::ReadOnly)) {QImageReader reader(&file);QImage image = reader.read(); }
-
支持从 QByteArray 间接读取(通过 QBuffer)。
4.1.3、读取图像信息
-
在不实际加载图像的情况下,获取图像元数据:
QImageReader reader("image.gif"); QSize size = reader.size(); // 图像尺寸 QImage::Format format = reader.imageFormat(); // 图像格式 int frameCount = reader.imageCount(); // 帧数(对多帧图像有效) qDebug() << "Size:" << size << "Format:" << format << "Frames:" << frameCount;
-
其他信息:text() 获取元数据(如 EXIF)、gamma() 获取伽马值。
4.1.4、读取多帧图像
-
对于支持多帧的格式(如 GIF、WebP 动画),可以逐帧读取:
QImageReader reader("animation.gif"); for (int i = 0; i < reader.imageCount(); ++i) {reader.jumpToImage(i);QImage frame = reader.read();// 处理每一帧 }
-
使用 loopCount() 检查动画循环次数(-1 表示无限循环)。
-
使用 nextImageDelay() 获取帧间延迟时间。
4.1.5、设置读取选项
-
缩放:读取时直接缩放图像,减少内存占用:
reader.setScaledSize(QSize(100, 100)); QImage scaledImage = reader.read();
-
裁剪:读取部分区域:
reader.setClipRect(QRect(50, 50, 100, 100));
-
格式偏好:强制指定输入格式(避免自动检测):
reader.setFormat("png");
4.2、QImageWriter:写入图像文件
QImageWriter 用于将 QImage 或 QPixmap 写入文件或设备,支持多种图像格式,并提供编码选项。
4.2.1、支持的图像格式
-
获取支持的格式:通过 QImageWriter::supportedImageFormats() 获取支持的写入格式。
QList<QByteArray> formats = QImageWriter::supportedImageFormats(); for (const QByteArray &format : formats) {qDebug() << "Supported write format:" << format; }
-
支持的格式通常与 QImageReader 一致,但某些格式可能只支持读取或写入。
4.2.2、将 QImage 或 QPixmap 写入文件或设备
-
写入文件:
QImage image(100, 100, QImage::Format_RGB32); QImageWriter writer("output.png"); if (writer.write(image)) {// 写入成功 } else {qDebug() << "Error:" << writer.errorString(); }
-
写入设备:
QFile file("output.jpg"); if (file.open(QIODevice::WriteOnly)) {QImageWriter writer(&file, "jpg");writer.write(image); }
-
QPixmap 需先转换为 QImage:
QPixmap pixmap; writer.write(pixmap.toImage());
4.2.3、设置写入选项
-
JPEG 质量(0-100,100 为最高质量):
writer.setQuality(90);
-
PNG 压缩级别(0-9,9 为最大压缩):
writer.setCompression(9);
-
元数据:通过 setText() 添加元数据(如描述、作者):
writer.setText("Description", "This is a test image");
4.3、QMovie:动态图像播放
QMovie 用于加载和播放动态图像(如 GIF、MNG),常用于 UI 中的动画显示。
4.3.1、加载和管理动画文件
-
加载 GIF:
QMovie *movie = new QMovie("animation.gif"); if (!movie->isValid()) {qDebug() << "Invalid movie file"; }
-
从 QByteArray 加载:
QByteArray data = // 从网络或其他来源获取 QBuffer buffer(&data); QMovie *movie = new QMovie(&buffer);
4.3.2、动画播放控制
-
基本控制:
movie->start(); // 开始播放 movie->stop(); // 停止 movie->setPaused(true); // 暂停 movie->jumpToFrame(5); // 跳转到指定帧 movie->setSpeed(200); // 播放速度(200% 表示 2 倍速)
-
状态查询:
QMovie::MovieState state = movie->state(); // Running, Paused, NotRunning int currentFrame = movie->currentFrameNumber();
4.3.3、获取当前帧
-
获取当前帧图像:
QImage frame = movie->currentImage(); QPixmap pixmap = movie->currentPixmap();
-
帧变化时通过信号 frameChanged(int) 捕获:
connect(movie, &QMovie::frameChanged, [](int frameNumber) {qDebug() << "Frame changed:" << frameNumber; });
4.3.4、将 QMovie 集成到 UI
-
结合 QLabel 显示动画:
QLabel *label = new QLabel; QMovie *movie = new QMovie("animation.gif"); label->setMovie(movie); movie->start();
-
调整大小:确保 QLabel 的 scaledContents 属性或电影的缩放设置正确:
movie->setScaledSize(QSize(100, 100));
-
可结合 QGraphicsView 或自定义控件实现更复杂的动画效果。
4.4、QImageIOHandler 与 QImageIOPlugin:自定义图像格式
QImageIOHandler 和 QImageIOPlugin 提供底层机制,用于扩展 Qt 的图像格式支持,适合开发者实现自定义图像格式的读写。
4.4.1、图像文件格式处理的底层机制
-
QImageIOHandler:抽象基类,定义了图像格式的读写接口(如 read()、write())。
-
QImageIOPlugin:插件类,用于注册新的图像格式处理器。
-
Qt 使用插件机制动态加载格式支持,内置格式(如 PNG、JPEG)由 Qt 提供插件实现。
4.4.2 如何实现自定义的图像格式插件
-
创建 QImageIOPlugin 子类:
class MyImagePlugin : public QImageIOPlugin {Q_OBJECTQ_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "myimage.json") public:Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;QImageIOHandler *create(QIODevice *device, const QByteArray &format) const override; };
-
创建 QImageIOHandler 子类:
class MyImageHandler : public QImageIOHandler { public:bool canRead() const override;bool read(QImage *image) override;bool write(const QImage &image) override; };
-
实现格式解析逻辑(例如,解析自定义文件头、像素数据等)。
-
提供插件元数据(如 JSON 文件):
{"Keys": ["myformat"] }
-
编译并安装插件到 Qt 的 imageformats 目录。
4.4.3、注册和发现图像插件
-
Qt 自动加载 imageformats 目录下的插件。
-
使用 QImageReader::supportedImageFormats() 检查是否成功注册。
-
手动注册(不推荐):
QImageIOHandler::setFactory(new MyImageHandlerFactory);
5、QPicture:记录和重放绘图指令
5.1、QPicture 的概念与用途
QPicture 是 Qt 提供的一个类,用于记录和重放 QPainter 的绘图指令。它本质上是一个轻量级的矢量图形容器,存储的是一系列绘图操作(如绘制线条、矩形、文本等),而不是像素数据。
5.1.1、概念
-
矢量性:QPicture 记录的是绘图指令(例如“画一条线”或“填充一个矩形”),而不是最终的像素图像。因此,它具有可伸缩性,适合在不同分辨率下重放而不会失真。
-
主要用途:
-
生成可伸缩的矢量图形:如 SVG 文件的简化替代,用于需要高质量缩放的场景。
-
保存自定义绘图:将复杂的绘图操作序列化保存,供后续重用。
-
跨平台绘图:在不同设备或上下文中重放相同的绘图操作。
-
调试绘图:记录绘图指令以分析或优化渲染过程。
-
5.1.2、与像素图像 (QImage/QPixmap) 的区别
-
QPicture 适合需要动态调整大小或重复渲染的场景(如图标、图表)。
-
QImage/QPixmap 适合需要像素级操作或直接显示的场景(如照片编辑、游戏贴图)。
特性 | QPicture | QImage/QPixmap |
---|---|---|
存储内容 | 绘图指令(矢量) | 像素数据(光栅) |
可伸缩性 | 无损缩放,适合高分辨率显示 | 缩放可能导致像素化 |
内存占用 | 通常较小(取决于指令复杂度) | 较大(取决于分辨率和颜色深度) |
用途 | 记录和重放绘图、矢量图形 | 图像处理、显示、像素级操作 |
性能 | 重放时需重新渲染,依赖绘图上下文 | 直接显示,适合快速渲染 |
格式支持 | 序列化到自定义格式或文件 | 支持 PNG、JPEG 等标准图像格式 |
5.2、记录和重放绘图
QPicture 的核心功能是通过 QPainter 记录绘图指令,并通过另一个 QPainter 重放这些指令。
5.2.1、使用 QPainter::begin(QPicture*) 开始记录
-
创建一个 QPicture 对象,并将其作为 QPainter 的绘制目标。
QPicture picture; QPainter painter; painter.begin(&picture); // 开始记录
-
执行记录:在 QPainter 上执行任意绘图操作,所有操作都会被记录到 QPicture 中。
painter.setPen(Qt::blue); painter.setBrush(Qt::yellow); painter.drawRect(10, 10, 100, 100); painter.setFont(QFont("Arial", 12)); painter.drawText(20, 50, "Hello, QPicture!");
-
使用 QPainter::end() 结束记录:调用 end() 完成记录,QPicture 保存了所有绘图指令。
-
使用 QPainter::drawPicture(QPicture) 重放记录的指令:在另一个 QPainter 上重放 QPicture 的绘图指令,通常在窗口、图像或其他绘图设备上。
void MyWidget::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.drawPicture(0, 0, picture); // 重放 QPicture }
5.3、QPicture 的存储与加载
QPicture 支持将绘图指令序列化到文件或内存,方便存储和传输。
5.3.1、将 QPicture 序列化到文件或内存
-
保存到文件:
QPicture picture; // ... 记录绘图指令 ... picture.save("drawing.pic"); // 保存为文件
-
保存到内存(QByteArray):
QByteArray data; QDataStream stream(&data, QIODevice::WriteOnly); picture.save(&stream); // 序列化到字节数组
-
文件格式:Qt 使用自定义的二进制格式存储 QPicture,不是标准图像格式(如 PNG)。文件扩展名通常为 .pic。
5.3.2、从文件或内存加载 QPicture
-
从文件加载:
QPicture picture; picture.load("drawing.pic"); // 从文件加载
-
从内存加载:
QByteArray data = // 从某处获取数据 QDataStream stream(&data, QIODevice::ReadOnly); picture.load(&stream); // 反序列化
5.4、QPicture 与 QImage/QPixmap 的转换
QPicture 和 QImage/QPixmap 之间可以相互转换,以结合矢量和光栅图形的优势。
5.4.1、将 QPicture 渲染到 QImage 或 QPixmap
-
渲染到 QImage:
QPicture picture; // ... 记录绘图指令 ... QImage image(200, 200, QImage::Format_ARGB32); image.fill(Qt::transparent); // 清空背景 QPainter painter(&image); painter.drawPicture(0, 0, picture); // 渲染 QPicture image.save("output.png"); // 保存为 PNG
-
渲染到 QPixmap:
QPixmap pixmap(200, 200); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.drawPicture(0, 0, picture);
5.4.2、从 QImage 或 QPixmap 创建 QPicture
记录绘制图像的指令:直接将 QImage 或 QPixmap 绘制到 QPicture 中,记录绘制操作。
QImage image("input.png");
QPicture picture;
QPainter painter(&picture);
painter.drawImage(0, 0, image); // 记录绘制 QImage 的指令
painter.end();
5.5、示例代码
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QPicture>
#include <QImage>class MyWidget : public QWidget {
protected:void paintEvent(QPaintEvent *) override {// 创建 QPicture 并记录绘图指令QPicture picture;QPainter painter(&picture);painter.setPen(Qt::red);painter.setBrush(Qt::green);painter.drawEllipse(50, 50, 100, 100);painter.drawText(60, 100, "QPicture Demo");painter.end();// 保存 QPicture 到文件picture.save("demo.pic");// 加载 QPictureQPicture loadedPicture;loadedPicture.load("demo.pic");// 重放 QPicture 到窗口QPainter widgetPainter(this);widgetPainter.drawPicture(0, 0, loadedPicture);// 渲染 QPicture 到 QImageQImage image(200, 200, QImage::Format_ARGB32);image.fill(Qt::transparent);QPainter imagePainter(&image);imagePainter.drawPicture(0, 0, loadedPicture);image.save("output.png");}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);MyWidget widget;widget.resize(200, 200);widget.show();return app.exec();
}
6、示例代码
6.1、使用 QLabel 显示静态图像和动画
#include <QApplication>
#include <QLabel>
#include <QMovie>
#include <QVBoxLayout>
#include <QWidget>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建主窗口QWidget window;QVBoxLayout *layout = new QVBoxLayout(&window);// 显示静态图像QLabel *imageLabel = new QLabel();QPixmap pixmap(":/images/sample.jpg"); // 假设资源文件中有图片imageLabel->setPixmap(pixmap.scaled(300, 300, Qt::KeepAspectRatio));layout->addWidget(imageLabel);// 显示动画 (GIF)QLabel *gifLabel = new QLabel();QMovie *movie = new QMovie(":/images/animation.gif"); // 假设有 GIF 文件gifLabel->setMovie(movie);movie->start();layout->addWidget(gifLabel);window.setLayout(layout);window.show();return app.exec();
}
6.2、在 Graphics View Framework 中处理和显示图像
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>int main(int argc, char *argv[]) {QApplication app(argc, argv);// 创建场景和视图QGraphicsScene scene;QGraphicsView view(&scene);view.setFixedSize(400, 400);// 加载并显示图像QPixmap pixmap(":/images/sample.jpg");QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap.scaled(300, 300, Qt::KeepAspectRatio));scene.addItem(item);// 设置初始位置item->setPos(50, 50);view.show();return app.exec();
}
6.3、自定义 Widget 中的图像绘制
#include <QApplication>
#include <QWidget>
#include <QPainter>class ImageWidget : public QWidget {
protected:void paintEvent(QPaintEvent *) override {QPainter painter(this);QPixmap pixmap(":/images/sample.jpg");painter.drawPixmap(0, 0, pixmap.scaled(size(), Qt::KeepAspectRatio));}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);ImageWidget widget;widget.resize(400, 300);widget.show();return app.exec();
}
6.4、从文件加载图像,显示,进行像素操作,保存到新文件
#include <QApplication>
#include <QLabel>
#include <QImage>
#include <QVBoxLayout>
#include <QPushButton>class ImageProcessor : public QWidget {
public:ImageProcessor() {QVBoxLayout *layout = new QVBoxLayout(this);label = new QLabel();QPushButton *processButton = new QPushButton("Process and Save");layout->addWidget(label);layout->addWidget(processButton);// 加载图像image = QImage(":/images/sample.jpg");label->setPixmap(QPixmap::fromImage(image));// 处理按钮点击connect(processButton, &QPushButton::clicked, this, &ImageProcessor::processImage);}private:QImage image;QLabel *label;void processImage() {// 示例:将图像转换为灰度QImage grayscale = image.convertToFormat(QImage::Format_Grayscale8);label->setPixmap(QPixmap::fromImage(grayscale));// 保存到新文件grayscale.save("output_grayscale.jpg");}
};int main(int argc, char *argv[]) {QApplication app(argc, argv);ImageProcessor window;window.show();return app.exec();
}
6.5、在后台线程中进行耗时图像处理,然后更新 UI
#include <QApplication>
#include <QLabel>
#include <QImage>
#include <QThread>
#include <QVBoxLayout>
#include <QPushButton>
#include <QDebug>class ImageWorker : public QObject {Q_OBJECT
public slots:void processImage(const QString &path) {QImage image(path);if (image.isNull()) {qDebug() << "Failed to load image:" << path;return;}// 模拟耗时操作:转换为灰度for (int y = 0; y < image.height(); ++y) {for (int x = 0; x < image.width(); ++x) {QRgb pixel = image.pixel(x, y);image.setPixel(x, y, qGray(pixel)); // 简化为灰度}}emit imageProcessed(image);}signals:void imageProcessed(const QImage &image);
};class ImageProcessor : public QWidget {Q_OBJECT
public:ImageProcessor() {QVBoxLayout *layout = new QVBoxLayout(this);label = new QLabel();QPushButton *processButton = new QPushButton("Process in Background");layout->addWidget(label);layout->addWidget(processButton);// 加载初始图像image = QImage("/home/user/QtProj/input.png");if (image.isNull()) {qDebug() << "Failed to load initial image";} else {label->setPixmap(QPixmap::fromImage(image));}// 设置线程和工作者thread = new QThread(this);worker = new ImageWorker();worker->moveToThread(thread);connect(processButton, &QPushButton::clicked, this, [=]() {worker->processImage("/home/user/QtProj/test.gif");});connect(worker, &ImageWorker::imageProcessed, this, &ImageProcessor::updateImage);connect(thread, &QThread::finished, worker, &QObject::deleteLater);thread->start();}~ImageProcessor() {// 确保线程在窗口销毁前退出if (thread->isRunning()) {thread->quit();thread->wait();}}private:QImage image;QLabel *label;QThread *thread;ImageWorker *worker;private slots:void updateImage(const QImage &processedImage) {if (!processedImage.isNull()) {label->setPixmap(QPixmap::fromImage(processedImage));} else {qDebug() << "Received null image";}}
};#include "main.moc" // 必须包含以生成 moc 文件int main(int argc, char *argv[]) {QApplication app(argc, argv);ImageProcessor window;window.show();return app.exec();
}
四. 字体和文本
提供字体管理和低级文本渲染功能。
-
QFont: 字体属性管理(大小、粗细、样式)。
-
QFontMetrics, QFontMetricsF: 字体度量,计算文本尺寸。
-
QFontDatabase: 系统字体资源访问。
-
QTextLayout, QTextOption: 高级文本布局和格式化。
-
QRawFont: 直接访问字体文件数据。
-
QTextFragment, QTextBlock: 低级文本结构(用于复杂文本渲染)。
-
QGlyphRun: 字形级文本渲染。
五. 事件和输入处理
处理 GUI 相关的用户输入和交互事件。
-
QMouseEvent: 鼠标点击、移动事件。
-
QHoverEvent: 鼠标悬停事件。
-
QWheelEvent: 鼠标滚轮事件。
-
QKeyEvent: 键盘输入事件。
-
QTouchEvent: 触摸输入事件。
-
QNativeGestureEvent: 平台特定手势(如 macOS 手势)。
-
QInputMethod, QInputMethodEvent: 输入法支持(虚拟键盘、语言切换)。
-
QDrag, QDropEvent: 拖放操作。
-
QClipboard: 剪贴板访问。
-
QTabletEvent: 数位板输入事件。
-
QEnterEvent (Qt 6): 鼠标进入/离开事件。
-
QExposeEvent: 窗口暴露事件。
-
QPlatformDrag: 平台特定的拖放实现。
六. OpenGL 和硬件加速
支持 OpenGL 和 Vulkan 渲染,适用于高性能图形。
-
QOpenGLContext: OpenGL 上下文管理。
-
QOpenGLFunctions, QOpenGLExtraFunctions: OpenGL API 封装。
-
QOpenGLFramebufferObject: 帧缓冲对象,用于离屏渲染。
-
QOpenGLShader, QOpenGLShaderProgram: 着色器支持。
-
QOpenGLTexture: 纹理管理。
-
QOpenGLBuffer: 顶点和索引缓冲区。
-
QOpenGLVertexArrayObject: 顶点数组对象。
-
QOpenGLTimerQuery, QOpenGLTimeMonitor: OpenGL 性能监控。
-
QAbstractOpenGLFunctions (Qt 6): 抽象化的 OpenGL 函数接口。
-
QVulkanInstance, QVulkanWindow (Qt 6): Vulkan 渲染支持。
七. 颜色和外观
管理颜色和外观设置。
-
QColor: 颜色表示(支持 RGB、HSV、CMYK)。
-
QPalette: 颜色方案管理(前景、背景等)。
-
QColorSpace (Qt 6): 颜色空间管理(支持 ICC 配置文件)。
-
QColormap: 颜色映射(主要用于旧平台)。
八. 图标和光标
支持图标和鼠标光标管理。
-
QIcon: 图标管理,支持多分辨率和状态。
-
QCursor: 鼠标光标样式和自定义形状。
-
QIconEngine: 自定义图标渲染引擎。
九. 平台和渲染后端
提供平台特定集成和渲染后端支持。
-
QPlatformIntegration: 平台特定的窗口系统集成(Windows、X11、Wayland 等)。
-
QRasterPaintEngine: 软件光栅化渲染引擎。
-
QPlatformSurface: 平台特定的渲染表面。
-
QPlatformTheme: 平台主题(如按钮样式、对话框风格)。
-
QPlatformGraphicsBuffer: 平台特定的图形缓冲区。
-
QPlatformSharedGraphicsCache: 共享图形缓存,加速渲染。
十. 国际化(GUI 相关)
支持 GUI 相关的字符编码和区域设置。
-
QTextCodec(部分):字符编码支持(仅限 GUI 文本显示)。
-
QLocale(部分):区域设置(仅限 GUI 格式,如日期、数字显示)。