# RulerImageWidget **Repository Path**: havealex/RulerImageWidget ## Basic Information - **Project Name**: RulerImageWidget - **Description**: 基于 Qt 5.14.2 / C++11 的图片标尺查看器,支持自适应缩放、拖拽平移、ROI 裁剪 - **Primary Language**: C++ - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-07-25 - **Last Updated**: 2026-07-25 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # RulerImageWidget 基于 Qt 5.14.2 / C++11 的图片标尺查看器,支持自适应缩放、拖拽平移、ROI 裁剪。 ## 项目结构 ``` RulerImageWidget/ ├── main.cpp # 程序入口,主窗口布局与信号槽连接 ├── rulerimagewidget.h # 核心控件头文件 ├── rulerimagewidget.cpp # 核心控件实现(标尺绘制、交互、裁剪) ├── RulerImageWidget.pro # Qt 工程文件 └── res/images/ ├── images.qrc # Qt 资源文件(前缀 /pictures) ├── 1.jpg # 默认加载图片 ``` ## 功能说明 | 功能 | 说明 | |------|------| | 图片加载 | 支持从本地文件系统加载图片,也支持从 Qt 资源文件加载 | | 自适应居中 | 图片加载后自动计算缩放比例,居中显示在标尺区域内 | | 横轴 / 纵轴标尺 | 根据当前缩放比例动态绘制像素坐标刻度,支持无限缩放 | | 鼠标缩放 | 滚轮以鼠标位置为中心进行缩放 | | 拖拽平移 | 左键或右键拖拽平移图片,标尺同步更新 | | ROI 框选 | 进入 ROI 模式后,左键拖拽绘制蓝色半透明选区,实时显示原始像素尺寸 | | ROI 裁剪 | 根据选区从原图裁剪并保存为 PNG / JPG / BMP | ## 技术点 ### 1. QPainter 自定义绘制 整个控件通过重写 `paintEvent` 完成所有绘制,绘制顺序: 1. **图片绘制** — `translate(offset)` → `scale(s)` → `drawImage(0, 0, img)`,通过 `QPainter::save/restore` 隔离变换状态 2. **标尺覆盖层** — 在图片上方绘制半透明标尺背景和刻度 3. **ROI 选区** — 蓝色半透明矩形 + 尺寸文字标注 开启了 `QPainter::Antialiasing` 和 `QPainter::SmoothPixmapTransform` 保证渲染质量。 ### 2. 动态标尺算法 标尺刻度根据缩放比例自适应调整步长,核心流程: ``` 目标像素间距 (50px) / 当前缩放比例 = 理想单位间距 ↓ 取 log10 找到最近的 10 的幂次基准 (1, 10, 100...) ↓ 按 1-2-5 进制细化 (1→2→5→10→20→50→100...) ↓ 步长 × 缩放比例 = 屏幕像素间距 ``` 每个主刻度区间等分为 5 个次级刻度,标注显示原始图像坐标值。 ### 3. 坐标系转换 存在三个坐标系之间的转换: | 坐标系 | 说明 | |--------|------| | 控件坐标 | 鼠标事件 `event->pos()` 返回的屏幕像素坐标 | | 画布坐标 | 经过 `offset` 和 `scale` 变换后的中间坐标 | | 图像坐标 | 原始图片的像素坐标(ROI 裁剪使用) | 转换公式: ``` 图像坐标 = (控件坐标 - imageOffset) / scale 画布坐标 = 图像坐标 × scale + imageOffset ``` ### 4. 鼠标事件处理 | 事件 | 普通模式 | ROI 模式 | |------|----------|----------| | 左键按下 | 开始拖拽平移 | 开始框选 | | 左键移动 | 平移图片 | 绘制选区矩形 | | 左键释放 | 结束平移 | 计算 ROI 图像坐标,发射 `roiChanged` 信号 | | 右键按下/移动/释放 | 平移图片 | 平移图片 | | 滚轮 | 以鼠标为中心缩放 | 以鼠标为中心缩放 | ### 5. 信号槽机制 ```cpp // 控件发射信号 void RulerImageWidget::roiChanged(); // ROI 选区完成时 // main.cpp 中连接 connect(rulerWidget, &RulerImageWidget::roiChanged, [=]() { btnCrop->setEnabled(true); }); ``` 按钮栏通过 Lambda 表达式直接捕获局部变量连接信号,无需定义额外的槽函数。 ### 6. 图片加载与自适应 - 使用 `QImageReader` 加载图片,开启 `setAutoTransform(true)` 自动处理 EXIF 旋转信息 - 自适应算法:取 `min(viewWidth/imgWidth, viewHeight/imgHeight) × 0.9` 作为缩放比例,留 10% 边距 - `resizeEvent` 中自动重新计算,窗口缩放时图片始终保持居中 ### 7. ROI 裁剪 - 选区以 `QRectF` 存储为原始图像坐标 - 裁剪时通过 `QRectF::intersected()` 限制在原图范围内 - 使用 `QImage::copy()` 提取子区域,支持保存为多种格式 ## 编译运行 使用 Qt Creator 打开 `RulerImageWidget.pro`,选择 Kit 后直接构建运行。 ```bash # 或命令行编译 qmake RulerImageWidget.pro make # Linux/macOS nmake # Windows MSVC mingw32-make # Windows MinGW ``` ## 环境要求 - Qt 5.14.2+ - C++11 - 模块:`core`、`gui`、`widgets`