目录
1.5、QBitmap 与 QImage、QPixmap 的对比说明
4.4、QImageIOHandler 与 QImageIOPlugin:自定义图像格式
5.4、QPicture 与 QImage/QPixmap 的转换
6.2、在 Graphics View Framework 中处理和显示图像
一. 窗口和屏幕管理
提供跨平台窗口创建、管理以及屏幕信息访问功能。
请跳转章节,此处不再重复: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_OBJECT Q_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");
// 加载 QPicture
QPicture loadedPicture;
loadedPicture.load("demo.pic");
// 重放 QPicture 到窗口
QPainter widgetPainter(this);
widgetPainter.drawPicture(0, 0, loadedPicture);
// 渲染 QPicture 到 QImage
QImage 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 格式,如日期、数字显示)。