一个使用 PyQt6 编写的桌面导入工具,用于从磁盘或存储卡中批量导入照片与视频,并提供去重、按日期组织、预览和统计等能力。整体交互设计的灵感来自一些专业相片管理软件的导入体验。
目前主要围绕以下几个目标设计:
- 导入前尽量看清楚会发生什么(预览树 + 统计)
- 自动去重,避免重复拷贝
- 不阻塞 UI,在大批量 RAW 文件时仍然可操作
-
文件扫描
- 从左侧“来源”树选择文件夹,点击“扫描”后,在后台线程中遍历文件。
- 支持常见图片与 RAW 格式:
JPG/JPEG/PNG/ARW/CR2/NEF/DNG/ORF/RW2,以及MP4/MOV等视频格式。 - 可选“递归扫描”,扫描子目录时会忽略隐藏目录(以
.开头)。
-
日期分组与导入预览
- 中间区域按“日期分组”展示文件,每个日期对应一个
DateSection网格。 - 右侧“目标位置”中,会根据当前设置计算导入路径,并构建一棵“目录结构预览树”。
- 预览树中可以看到导入后将创建哪些子目录、每个目录下会导入多少文件。
- 中间区域按“日期分组”展示文件,每个日期对应一个
-
去重逻辑
- 扫描完成后,会根据目标路径计算每个源文件的“导入目标文件路径”。
- 如果目标位置已经存在同名文件,并且通过内容比对(例如 MD5)判定为相同:
- 该源文件会被标记为“重复”,在中间网格中隐藏、且取消勾选;
- 在统计中计入“重复跳过”的数量;
- 不会出现在右侧导入结果预览中,也不会再次拷贝。
-
选择与勾选逻辑
- 每个缩略图条目旁边有一个勾选框,控制“是否导入该文件”。
- 点击缩略图区域只会更新右侧预览,不会影响勾选状态。
- 扫描完成后,默认会勾选所有非重复文件,方便“一键全选导入”。
- 勾选状态会实时反映到右侧目录预览树和统计中。
-
缩略图开关与延迟加载
- 右侧“导入设置”中提供选项:
生成缩略图(可能较慢)
- 默认关闭缩略图生成:
- 扫描时仍会列出所有文件,但使用统一灰色占位图标,不进行任何图片解码,CPU 占用较低。
- 仅当勾选此选项时才会生成缩略图:
- 缩略图在后台线程中加载,不阻塞 UI。
- 对 RAW 文件优先尝试读取内嵌 JPEG 缩略图;如果没有,则使用
rawpy.postprocess(half_size=True)生成较小图像。
- 已实现视口级别的延迟加载:
- 仅对当前滚动区域内“看得见”的条目批量生成缩略图,每批最多处理固定数量(例如 32 个)。
- 向下滚动时,新的可见条目会被检测并加入下一批加载队列。
- 对大批量文件时,不会一次性解码全部缩略图,大幅降低 CPU 和内存压力。
- 右侧“导入设置”中提供选项:
-
预览面板
- 右侧“预览”区域显示当前选中文件的大图和基本信息。
- 与中间网格/勾选逻辑解耦:预览只是“查看”,勾选才决定是否导入。
- 对 RAW 文件,预览会按需解码单张图像。
-
导入统计
- 右下角“统计”区域会展示:
- 已选择的文件数量;
- 预计复制大小(如果实现);
- 重复文件数量等。
- 勾选 / 去重 / 设置变更后会自动刷新统计。
- 右下角“统计”区域会展示:
-
性能与稳定性
- 文件扫描、缩略图加载、实际导入操作均放在后台线程,避免卡死 UI。
- 对目录结构重建、导入预览等操作增加了 debounce(延迟合并刷新),减少重复计算。
- 提供 cProfile 支持,可以快速分析性能瓶颈。
项目基于:
- Python 3.12(
.python-version中指定) - PyQt6
- rawpy
- imageio
- numpy
依赖信息在 pyproject.toml 中已经列出,建议使用你熟悉的工具(如 uv、pip 或 poetry)安装。
示例(使用 pip,仅供参考):
pip install -e .或直接根据 pyproject.toml 中的依赖列表安装。
在项目根目录下:
python3 main.py程序启动后,会打开主窗口。
-
选择来源文件夹
- 在左侧“来源”树中选择要导入的文件夹。
- 勾选“递归扫描”可包含子目录,不勾选则只扫描当前目录。
-
扫描文件
- 点击“扫描”按钮开始扫描。
- 中间区域会按日期分组显示文件,每个条目带一个勾选框。
- 默认情况下不生成缩略图,只显示占位图(可以在右侧打开缩略图)。
-
调整导入设置
- 在右侧“导入设置”中:
- 选择“按日期组织文件”与否;
- 设置“日期格式”(如
YYYY-MM-DD、YYYY/MM/DD等); - 选择时间源:
文件修改时间(默认)拍摄时间 (EXIF)(如果文件带 EXIF 信息);
- 可选填写“自定义模板”,如:
{year}/{month:02d}/{day:02d}{year}-{month}-{day}等。
- 在“目标位置”中选择导入的主目录,预览树会根据当前设置实时更新。
- 在右侧“导入设置”中:
-
勾选要导入的文件
- 中间网格每个条目旁边的勾选框控制是否导入该文件。
- 扫描和去重完成后,默认勾选所有非重复文件。
- 点击缩略图区域只会更新右侧预览,不改变勾选状态。
- 去重后的重复文件会被自动隐藏并取消勾选,不会出现在预览树中。
-
预览导入结果
- 在右侧“目标位置”的树中,可以看到导入后将创建的目录结构和每个目录下的文件计数。
- “统计”区域显示当前勾选的文件数量等信息。
-
执行导入
- 核对无误后,点击“导入”按钮开始实际拷贝。
- 导入过程在后台线程处理,同时更新进度与状态。
- 缩略图开关
右侧“导入设置”中有一项:
生成缩略图(可能较慢)
默认关闭,关闭时:
- 仅显示灰色占位图;
- 不对任何文件进行缩略图解码;
- 在大量 RAW 文件场景下,CPU 占用明显降低。
勾选开启后:
- 扫描时仍然先用占位符把所有文件列出来,保证 UI 流畅;
- 后台线程会为部分文件生成真实缩略图。
- 视口级延迟加载
为进一步减少负载,实现了“只为视口附近项目生成缩略图”的逻辑:
- 每次扫描或滚动时,会计算当前 ScrollArea 的可见区域;
- 遍历每个日期分组的
QListWidget,只处理与可见区域有交集的条目; - 对这些条目中尚未加载过的文件,按批加入缩略图加载队列(每批最多约 32 个);
- 后台线程依次为这些文件生成缩略图,并在完成后更新对应条目的图标。
这样在成千上万张图的场景下,也只会为“眼前看到的”和“附近”少量项目解码缩略图,大幅减少不必要的计算。
为方便排查性能问题,程序支持通过 cProfile 进行性能分析。
大致用法(示例,具体以 main.py 实现为准):
python3 main.py --profile --profile-output myrun.prof运行结束后,可以使用:
python3 -m pstats myrun.prof查看性能热点,例如缩略图加载、目录扫描、去重等部分的时间占比。
- 支持常见 RAW 格式(含 RW2)与常见视频格式;
- 后台线程扫描,UI 不随文件数量线性卡死;
- 自动按日期分组显示,支持多种日期格式及自定义模板;
- 导入前通过目录树预览将要创建的目录结构和文件分布;
- 基于目标路径和内容比对的去重逻辑,避免重复导入;
- 缩略图默认关闭,可按需开启,并实现“只为视口附近项目生成缩略图”的延迟加载;
- 勾选逻辑与预览解耦:勾选控制导入,点击控制预览;
- 提供基础性能分析支持,方便进一步优化。
后续可以在此基础上继续扩展,例如:
- 更细粒度的导入规则(按相机型号、镜头、评分等);
- 磁盘级缩略图缓存,避免重复 RAW 解码;
- 更完善的错误提示和日志系统等。